﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace ImageProcessing
{

	//This is intended to take the place of the ColorConversions class
	public static class BitmapConversions
	{
		private static double[,] adRGBtoYIQ = new double[,] {
			{0.298895,0.586622,0.114482},
			{.595716, -.274453, -.321263},
			{.211456, -.522591, .311135}
		};

		private static double[,] adYIQtoRGB = new double[,] { 
			{1, .9563, .6210},
			{1, -.2721, -.6474},
			{1, 0.1070,1.7046}
		};

		private static double[,] adPitasRGBtoHSI = new double[,] {
			{0.5773503, 0.5773503,0.5773503},
			{0, 0.7071068, -0.7071068},
			{0.8164966, -0.4082483,-0.4082483}
		};

		private static double[,] adPitasHSItoRGB = new double[,] {
			{0.5773503, 0, 0.8164966},
			{ 0.5773503, 0.7071068, -0.4082483},
			{0.5773503, -0.7071068, -0.4082483}
		};

		private static double[,] adPrattRGBtoHSI = new double[,] {
			{0.3333333,0.3333333,0.3333333},
			{-0.4082483,-0.4082483,0.8164966},
			{0.4082483,-0.4082483,0}
		};

		private static double[,] adPrattHSItoRGB = new double[,] {
			{1, -t, 3*t },
			{1, -t, -3*t},
			{1, 2*t, 0 }
		};

		private static double t = 1 / Math.Sqrt(6);

		public static double[, ,] NormalizeRGB(Bitmap bmIn)
		{
			double[, ,] adNormal = new double[bmIn.Width, bmIn.Height, 3];
			int k;
			#region Image pointer setup
			BitmapData srcBitData;
			Rectangle rectSrc = new Rectangle(0, 0, bmIn.Width, bmIn.Height);
			srcBitData = bmIn.LockBits(rectSrc, ImageLockMode.ReadOnly, bmIn.PixelFormat);
			int strideSrc = srcBitData.Stride;

			IntPtr srcPtr = srcBitData.Scan0;
			int imageBPP = Image.GetPixelFormatSize(bmIn.PixelFormat);
			int srcBytePP = imageBPP / 8;
			#endregion Image pointer setup

			unsafe
			{
				byte* sptr = (byte*)(void*)srcPtr;
				for (int j = 0; j < bmIn.Height; j++)
				{
					k = j * strideSrc;
					for (int i = 0; i < bmIn.Width; i++)
					{
						adNormal[i, j, 0] = sptr[k + i * srcBytePP] / 255.0;
						if (srcBytePP > 1)
						{
							adNormal[i, j, 1] = sptr[k + i * srcBytePP + 1] / 255.0;
							adNormal[i, j, 2] = sptr[k + i * srcBytePP + 2] / 255.0;
						} //end if
						else //make them all the same (simulate gray level)
						{
							adNormal[i, j, 1] = sptr[k + i * srcBytePP] / 255.0;
							adNormal[i, j, 2] = sptr[k + i * srcBytePP] / 255.0;
						}
					} //end for
				} //end for
			} //end unsafe

			bmIn.UnlockBits(srcBitData);
			return adNormal;
		}

		public static Bitmap UnNormalizeRGB(double[, ,] adNormal, int nWidth, int nHeight, bool doClamp, PixelFormat pixelFormat)
		{
			Bitmap bmIn = new Bitmap(nWidth, nHeight, pixelFormat);
			int bytePP = (int)pixelFormat / 8;
			int k;
			int l;
			#region Image pointer setup
			BitmapData srcBitData;
			Rectangle rectSrc = new Rectangle(0, 0, bmIn.Width, bmIn.Height);
			srcBitData = bmIn.LockBits(rectSrc, ImageLockMode.ReadOnly, bmIn.PixelFormat);
			int strideSrc = srcBitData.Stride;

			IntPtr srcPtr = srcBitData.Scan0;
			int imageBPP = Image.GetPixelFormatSize(bmIn.PixelFormat);
			int srcBytePP = imageBPP / 8;
			#endregion Image pointer setup


			unsafe
			{
				byte* dptr = (byte*)(void*)srcPtr;

				for (int j = 0; j < nHeight; j++)
				{
					k = j * strideSrc;
					for (int i = 0; i < nWidth; i++)
					{
						l = i * srcBytePP;
						if (doClamp)
						{
							dptr[k + l] = (byte)Math.Max(Math.Min(255.0, adNormal[i, j, 0] * 255.0), 0);
							if (bytePP > 1)
							{
								dptr[k + l + 1] = (byte)Math.Max(Math.Min(255.0, adNormal[i, j, 1] * 255.0), 0);
								dptr[k + l + 2] = (byte)Math.Max(Math.Min(255.0, adNormal[i, j, 2] * 255.0), 0);
								if (bytePP >= 4)
								{
									dptr[k + l + 3] = 255;
								} //end if
							} //end if


						} //end if
						else //normalize based on min and max
						{
							dptr[k + l] = (byte)Math.Max(Math.Min(255.0, adNormal[i, j, 0] * 255.0), 0);
							if (bytePP > 1)
							{
								dptr[k + l + 1] = (byte)Math.Max(Math.Min(255.0, adNormal[i, j, 1] * 255.0), 0);
								dptr[k + l + 2] = (byte)Math.Max(Math.Min(255.0, adNormal[i, j, 2] * 255.0), 0);
								if (bytePP >= 4)
								{
									dptr[k + l + 3] = 255;
								} //end if
							}
						}


					} //end for
				} //end for

			} //end unsafe

			bmIn.UnlockBits(srcBitData);
			return bmIn;


		}//end UnNormalizeRGB

		public static double[, ,] YIQConversion(double[, ,] adRGB, int nWidth, int nHeight, bool isRGBtoYIQ)
		{
			return null;
		}

	}
}
